package com.by.common.controller;

import com.by.common.bean.ResultBean;
import com.by.common.ex.ValidateException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Ye QS
 * @version 0.1
 * @className BaseController
 * @description
 * @date 2024/9/5 14:36
 * @since jdk11
 */

/**
 * 公共基类控制器，用于封装通用的操作和返回结果处理。
 */
public abstract class BaseController {

    /**
     * 成功状态码常量，通常表示操作成功。
     */
    private final int SUCCESS = 200;

    /**
     * 失败状态码常量，通常表示操作失败或错误。
     */
    private final int FAIL = 0;

    /**
     * 创建一个带有消息的成功响应对象。
     *
     * @param msg 操作成功的提示信息。
     * @return 包含指定消息的ResultBean实例。
     */
    protected ResultBean success(String msg) {
        return convert(SUCCESS, msg, null);
    }

    /**
     * 创建一个带有数据及消息的成功响应对象。
     *
     * @param msg  操作成功的提示信息。
     * @param data 返回给客户端的数据实体。
     * @return 包含指定消息与数据的ResultBean实例。
     */
    protected ResultBean success(String msg, Object data) {
        return convert(SUCCESS, msg, data);
    }

    /**
     * 创建一个带有消息的失败响应对象。
     *
     * @param msg 操作失败的提示信息。
     * @return 包含指定消息的ResultBean实例。
     */
    protected ResultBean fail(String msg) {
        return convert(FAIL, msg, null);
    }

    /**
     * 创建一个带有数据及消息的失败响应对象。
     *
     * @param msg  操作失败的提示信息。
     * @param data 返回给客户端的数据实体（如果有的话）。
     * @return 包含指定消息与数据的ResultBean实例。
     */
    protected ResultBean fail(String msg, Object data) {
        return convert(FAIL, msg, data);
    }

    /**
     * 根据保存操作的结果创建相应的ResultBean对象。
     *
     * @param rs 数据库操作影响的行数，1 表示成功。
     * @return 如果rs为1，则返回包含“保存成功”消息的ResultBean；否则返回含有“保存失败”的ResultBean。
     */
    protected ResultBean saveResult(int rs) {
        return rs == 1 ? success("保存成功") : fail("保存失败");
    }

    /**
     * 根据更新操作的结果创建相应的ResultBean对象。
     *
     * @param rs 数据库操作影响的行数，1 表示成功。
     * @return 如果rs为1，则返回包含“修改成功”消息的ResultBean；否则返回含有“修改失败”的ResultBean。
     */
    protected ResultBean updateResult(int rs) {
        return rs == 1 ? success("修改成功") : fail("修改失败");
    }

    /**
     * 根据删除操作的结果创建相应的ResultBean对象。
     *
     * @param rs 数据库操作影响的行数，1 表示成功。
     * @return 如果rs为1，则返回包含“删除成功”消息的ResultBean；否则返回含有“删除失败”的ResultBean。
     */
    protected ResultBean deleteResult(int rs) {
        return rs == 1 ? success("删除成功") : fail("删除失败");
    }

    /**
     * 将传入的状态码、消息以及额外数据转换成统一格式的ResultBean对象。
     *
     * @param code 状态码，用于区分请求是否成功。
     * @param msg  提供给客户端的消息描述。
     * @param data 额外的数据负载。
     * @return 构造好的ResultBean实例。
     */
    ResultBean convert(int code, String msg, Object data) {
        return new ResultBean<>(code, msg, data);
    }

    /**
     * 验证辅助方法，用于处理表单提交数据的验证结果。
     * <p>
     * 该方法检查提供的BindingResult对象中是否包含任何字段级错误，
     * 如果存在，则收集所有错误信息并抛出自定义异常ValidateException。
     * 这有助于统一处理用户输入数据不合法的情况，并向调用者提供详细的错误报告。
     *
     * @param result BindingResult对象，包含了校验过程中的所有错误详情。
     * @throws ValidateException 当检测到验证失败时抛出此异常，附带具体的错误信息。
     */
    protected void validate(BindingResult result) {
        // 获取验证信息
        List<FieldError> fieldErrors = result.getFieldErrors();

        if (fieldErrors.size() > 0) {
            Map<String, String> error = new HashMap<>();
            // 遍历错误字段
            fieldErrors.forEach(el -> {
                error.put(el.getField(), el.getDefaultMessage());
            });
            // 将异常信息抛给虚拟机
            throw new ValidateException(error);
        }
    }
}